package vip.liux.backend.application.serviceImpl.pay.client;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.util.Assert;
import vip.liux.backend.application.service.pay.*;
import vip.liux.backend.application.service.pay.dto.order.PayOrderDto;
import vip.liux.backend.application.service.pay.dto.refund.PayRefundDetailsDto;
import vip.liux.backend.application.service.pay.dto.transfer.PayTransferDto;
import vip.liux.backend.application.service.pay.dto.wallet.PayWalletTransactionDto;
import vip.liux.contracts.infrastructure.pay.dto.order.ClientPayOrderDto;
import vip.liux.contracts.infrastructure.pay.dto.order.PayOrderUnifiedDto;
import vip.liux.contracts.infrastructure.pay.dto.refund.ClientPayRefundDto;
import vip.liux.contracts.infrastructure.pay.dto.refund.PayRefundUnifiedDto;
import vip.liux.contracts.infrastructure.pay.dto.transfer.ClientPayTransferDto;
import vip.liux.contracts.infrastructure.pay.dto.transfer.PayTransferUnifiedDto;
import vip.liux.contracts.infrastructure.pay.impl.AbstractPayClient;
import vip.liux.contracts.infrastructure.pay.impl.NonePayClientConfig;
import vip.liux.contracts.shared.enums.pay.*;
import vip.liux.contracts.shared.kits.ApplicationKit;
import vip.liux.core.exception.BusinessException;

import java.util.Map;

import static vip.liux.contracts.shared.enums.ErrorCode.*;


/**
 * 钱包支付的 PayClient 实现类
 *
 * @author jason
 */
@Slf4j
public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
    public static final String WALLET_ID_KEY = "walletId";

    private PayWalletService wallService;
    private PayWalletTransactionService walletTransactionService;

    private PayOrderService orderService;
    private PayRefundService refundService;
    private PayTransferService transferService;

    public WalletPayClient(Long channelId, NonePayClientConfig config) {
        super(channelId, PayChannelCode.WALLET.getCode(), config);
    }

    @Override
    protected void doInit() {
        if (wallService == null) {
            wallService = ApplicationKit.getBean(PayWalletService.class);
        }
        if (walletTransactionService == null) {
            walletTransactionService = ApplicationKit.getBean(PayWalletTransactionService.class);
        }
    }

    @Override
    protected ClientPayOrderDto doUnifiedOrder(PayOrderUnifiedDto reqDto) {
        try {
            Long walletId = MapUtils.getLong(reqDto.getChannelExtras(), WALLET_ID_KEY);
            Assert.notNull(walletId, "钱包编号");
            PayWalletTransactionDto transaction = wallService.orderPay(walletId,
                    reqDto.getOutTradeNo(), reqDto.getPrice());
            return ClientPayOrderDto.successOf(transaction.getSeqNo(), transaction.getCreatorId(),
                    transaction.getCreationTime(),
                    reqDto.getOutTradeNo(), transaction);
        } catch (Throwable ex) {
            log.error("[doUnifiedOrder][reqDto({}) 异常]", reqDto, ex);
            String errorCode = String.valueOf(INTERNAL_SERVER_ERROR.getValue());
            String errorMsg = INTERNAL_SERVER_ERROR.getDesc();
            if (ex instanceof BusinessException businessException) {
                errorCode = businessException.getCode();
                errorMsg = businessException.getMessage();
            }
            return ClientPayOrderDto.closedOf(String.valueOf(errorCode), errorMsg,
                    reqDto.getOutTradeNo(), "");
        }
    }

    @Override
    protected ClientPayOrderDto doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
        throw new UnsupportedOperationException("钱包支付无支付回调");
    }

    @Override
    protected ClientPayOrderDto doGetOrder(String outTradeNo) {
        if (orderService == null) {
            orderService = ApplicationKit.getBean(PayOrderService.class);
        }
        PayOrderDto orderDto = orderService.getByOrderNo(outTradeNo);
        // 支付交易拓展单不存在， 返回关闭状态
        if (orderDto == null) {
            return ClientPayOrderDto.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getValue()),
                    PAY_ORDER_EXTENSION_NOT_FOUND.getDesc(), outTradeNo, "");
        }
        // 关闭状态
        if (PayOrderStatus.isClosed(orderDto.getStatus())) {
            return ClientPayOrderDto.closedOf(orderDto.getChannelErrorCode(),
                    orderDto.getChannelErrorMsg(), outTradeNo, "");
        }
        // 成功状态
        if (PayOrderStatus.isSuccess(orderDto.getStatus())) {
            PayWalletTransactionDto walletTransaction = walletTransactionService.getWalletTransaction(
                    String.valueOf(orderDto.getId()), PayWalletBizType.PAYMENT);
            Assert.notNull(walletTransaction, "支付单 " + outTradeNo + " 钱包流水不能为空");
            return ClientPayOrderDto.successOf(walletTransaction.getSeqNo(), walletTransaction.getCreatorId(),
                    walletTransaction.getCreationTime(), outTradeNo, walletTransaction);
        }
        // 其它状态为无效状态
        log.error("[doGetOrder] 支付单 {} 的状态不正确", outTradeNo);
        throw new IllegalStateException(String.format("支付单[%s] 状态不正确", outTradeNo));
    }

    @Override
    protected ClientPayRefundDto doUnifiedRefund(PayRefundUnifiedDto reqDto) {
        try {
            PayWalletTransactionDto payWalletTransaction = wallService.orderRefund(reqDto.getOutRefundNo(),
                    reqDto.getRefundPrice(), reqDto.getReason());
            return ClientPayRefundDto.successOf(payWalletTransaction.getSeqNo(), payWalletTransaction.getCreationTime(),
                    reqDto.getOutRefundNo(), payWalletTransaction);
        } catch (Throwable ex) {
            log.error("[doUnifiedRefund][reqDOT({}) 异常]", reqDto, ex);
            String errorCode = String.valueOf(INTERNAL_SERVER_ERROR.getValue());
            String errorMsg = INTERNAL_SERVER_ERROR.getDesc();
            if (ex instanceof BusinessException businessException) {
                errorCode = businessException.getCode();
                errorMsg = businessException.getMessage();
            }
            return ClientPayRefundDto.failureOf(String.valueOf(errorCode), errorMsg,
                    reqDto.getOutRefundNo(), "");
        }
    }

    @Override
    protected ClientPayRefundDto doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
        throw new UnsupportedOperationException("钱包支付无退款回调");
    }

    @Override
    protected ClientPayRefundDto doGetRefund(String outTradeNo, String outRefundNo) {
        if (refundService == null) {
            refundService = ApplicationKit.getBean(PayRefundService.class);
        }
        PayRefundDetailsDto payRefund = refundService.getRefundByRefundNo(outRefundNo);
        // 支付退款单不存在， 返回退款失败状态
        if (payRefund == null) {
            return ClientPayRefundDto.failureOf(String.valueOf(REFUND_NOT_FOUND), REFUND_NOT_FOUND.getDesc(),
                    outRefundNo, "");
        }
        // 退款失败
        if (PayRefundStatus.isFailure(payRefund.getStatus())) {
            return ClientPayRefundDto.failureOf(payRefund.getChannelErrorCode(), payRefund.getChannelErrorMsg(),
                    outRefundNo, "");
        }
        // 退款成功
        if (PayRefundStatus.isSuccess(payRefund.getStatus())) {
            PayWalletTransactionDto walletTransaction = walletTransactionService.getWalletTransaction(
                    String.valueOf(payRefund.getId()), PayWalletBizType.PAYMENT_REFUND);
            Assert.notNull(walletTransaction, "支付退款单 " + outRefundNo + " 钱包流水不能为空");
            return ClientPayRefundDto.successOf(walletTransaction.getSeqNo(), walletTransaction.getCreationTime(),
                    outRefundNo, walletTransaction);
        }
        // 其它状态为无效状态
        log.error("[doGetRefund] 支付退款单 {} 的状态不正确", outRefundNo);
        throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo));
    }

    @Override
    public ClientPayTransferDto doUnifiedTransfer(PayTransferUnifiedDto reqDto) {
        try {
            Long walletId = Long.parseLong(reqDto.getUserAccount());
            PayWalletTransactionDto transaction = wallService.addWalletBalance(walletId, String.valueOf(reqDto.getOutTransferNo()),
                    PayWalletBizType.TRANSFER, reqDto.getPrice());
            return ClientPayTransferDto.successOf(transaction.getSeqNo(), transaction.getCreationTime(),
                    reqDto.getOutTransferNo(), transaction);
        } catch (Throwable ex) {
            log.error("[doUnifiedTransfer][reqDto({}) 异常]", reqDto, ex);
            String errorCode = String.valueOf(INTERNAL_SERVER_ERROR.getValue());
            String errorMsg = INTERNAL_SERVER_ERROR.getDesc();
            if (ex instanceof BusinessException businessException) {
                errorCode = businessException.getCode();
                errorMsg = businessException.getMessage();
            }
            return ClientPayTransferDto.closedOf(String.valueOf(errorCode), errorMsg,
                    reqDto.getOutTransferNo(), "");
        }
    }

    @Override
    protected ClientPayTransferDto doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
        throw new UnsupportedOperationException("钱包支付无转账回调");
    }

    @Override
    protected ClientPayTransferDto doGetTransfer(String outTradeNo) {
        if (transferService == null) {
            transferService = ApplicationKit.getBean(PayTransferService.class);
        }
        // 获取转账单
        PayTransferDto transfer = transferService.getTransferByNo(outTradeNo);
        // 转账单不存在，返回关闭状态
        if (transfer == null) {
            return ClientPayTransferDto.closedOf(String.valueOf(PAY_ORDER_EXTENSION_NOT_FOUND.getValue()),
                    PAY_ORDER_EXTENSION_NOT_FOUND.getDesc(), outTradeNo, "");
        }
        // 关闭状态
        if (PayTransferStatus.isClosed(transfer.getStatus())) {
            return ClientPayTransferDto.closedOf(transfer.getChannelErrorCode(),
                    transfer.getChannelErrorMsg(), outTradeNo, "");
        }
        // 成功状态
        if (PayTransferStatus.isSuccess(transfer.getStatus())) {
            PayWalletTransactionDto walletTransaction = walletTransactionService.getWalletTransaction(
                    String.valueOf(transfer.getId()), PayWalletBizType.TRANSFER);
            Assert.notNull(walletTransaction, "转账单 " + outTradeNo + " 钱包流水不能为空");
            return ClientPayTransferDto.successOf(walletTransaction.getSeqNo(), walletTransaction.getCreationTime(),
                    outTradeNo, walletTransaction);
        }
        // 处理中状态
        if (PayTransferStatus.isProcessing(transfer.getStatus())) {
            return ClientPayTransferDto.processingOf(transfer.getChannelTransferNo(),
                    outTradeNo, transfer);
        }
        // 等待状态
        if (PayTransferStatus.isWaiting(transfer.getStatus())) {
            return ClientPayTransferDto.waitingOf(transfer.getChannelTransferNo(),
                    outTradeNo, transfer);
        }
        // 其它状态为无效状态
        log.error("[doGetTransfer] 转账单 {} 的状态不正确", outTradeNo);
        throw new IllegalStateException(String.format("转账单[%s] 状态不正确", outTradeNo));
    }
}
